Neste notebook estarão presentes os códigos que foram utilizados para gerar os gráficos dos dados analisados durante a elaboração do relatório. Para isto, foram utilizadas as bibliotecas: pandas, numpy, matplotlib, ploty e seaborn. As duas primeiras fornecem, principalmente, ferramentas para a análise de dados, enquanto matplotlib e seaborn são voltadas à geração dos gráficos. Já a ploty será utiliza para gerar um mapa do Brasil, contendo neste informações relevantes para as análises. Cada trecho de código teremos a explicação de dois pontos principais:
Além da demonstração do código, também seguirá uma explicação da lógica utilizada para gerar e plotar as informações requeridas para análisar determinada hipótese.
Por último, sempre que relevante, será feita também uma explicação do tratamento dos dados que foi utilizado para ser possível extrair a informação da maneira mais clara e direta possível.
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import matplotlib.pyplot as plt
import seaborn as sns
pd.plotting.register_matplotlib_converters()
%matplotlib inline
def region_indexes(number: str) -> str:
indexes = {'Norte': ['11', '12', '13', '14', '15', '16', '17'],
'Nordeste': ['21', '22', '23', '24', '25', '26', '27', '28', '29'],
'Sudeste': ['31', '32', '33', '35'],
'Sul': ['41', '42', '43'],
'Centro-Oeste': ['50', '51', '52', '53']
}
if number in indexes['Norte']:
return 'Norte'
elif number in indexes['Nordeste']:
return 'Nordeste'
elif number in indexes['Sudeste']:
return 'Sudeste'
elif number in indexes['Sul']:
return 'Sul'
else:
return 'Centro-Oeste'
def set_region(row) -> 'row':
number = str(row.id_municipio)
first_digits = number[:2] # Escolhendo os dois primeiros digitos do identificador
region = region_indexes(first_digits) # Localizando a regiao atraves desses digitos
row.id_municipio = f'{region}'
return row
def set_rede(row) -> 'row':
if row.rede == 'municipal' or row.rede == 'estadual' or row.rede == 'federal':
row.rede = 'publica'
return row
Muitas vezes dados relevantes foram encontradas em arquivos csv que continham a identificação dos municípios através do seu código. Porém, como frequentemente uma estratégia mais interessante seria analisar a região de cada município, criei a função 'region_index' para, a partir do prefixo, definir a região. A relação entre o prefixo e a região foi definida com base nas informações de códigos do ibge.
A função 'set_region' foi definida para realizar essa substuição, na tabela csv, do indice da região por sua respectiva região.
A função 'set_rede', utilizada para tratar os dados da analise de ensino, tem por objetivo identificar se uma instituição pertence a esfera pública ou privada. Para isso, caso a instituição seja municipal, estadual ou federal, setamos o atributo 'rede' == 'publica'.
O primeiro e mais simples gráfico utilizado no relatório é um gráfico de barras para demonstrar a diferença nas taxas de crianças matriculadas em pré-escolas nas diferentes regiões do Brasil. Para isso, utilizei a base de dados do ibge: 'basedosdados.br_abrinq_oca.primeira_infancia_municipios', encontrada no site base dos dados [https://basedosdados.org/]. Os dados contendo informações de interesse foram salvos como 'taxa_bruta_mais_linhas.csv'. Carregando os dados e observando suas linhas iniciais temos:
data_matricula = pd.read_csv("taxa_bruta_mais_linhas.csv")
data_matricula.head()
| id_municipio | ano | taxa_bruta_mat_pre_escola | |
|---|---|---|---|
| 0 | 1100015 | 2010 | 54.6 |
| 1 | 1100015 | 2011 | 60.6 |
| 2 | 1100015 | 2012 | 62.1 |
| 3 | 1100015 | 2013 | 67.0 |
| 4 | 1100015 | 2014 | 45.2 |
data_matricula = data_matricula.apply(set_region, axis='columns')
data_matricula.head()
| id_municipio | ano | taxa_bruta_mat_pre_escola | |
|---|---|---|---|
| 0 | Norte | 2010.0 | 54.6 |
| 1 | Norte | 2011.0 | 60.6 |
| 2 | Norte | 2012.0 | 62.1 |
| 3 | Norte | 2013.0 | 67.0 |
| 4 | Norte | 2014.0 | 45.2 |
# separando por regiao
municipios_nordeste = data_matricula.loc[data_matricula.id_municipio == 'Nordeste']
municipios_norte = data_matricula.loc[data_matricula.id_municipio == 'Norte']
municipios_centro = data_matricula.loc[data_matricula.id_municipio == 'Centro-Oeste']
municipios_sul = data_matricula.loc[data_matricula.id_municipio == 'Sul']
municipios_sudeste = data_matricula.loc[data_matricula.id_municipio == 'Sudeste']
municipios_por_regiao = [municipios_nordeste, municipios_norte, municipios_centro, municipios_sul, municipios_sudeste]
media_regional = {}
# calculando a taxa media de cada regiao
for municipios in municipios_por_regiao:
taxa_total_regiao = municipios.taxa_bruta_mat_pre_escola.sum() # taxa total da regiao
municipios_na_regiao = len(municipios) # numero de municipios na regiao
taxa_media = taxa_total_regiao / municipios_na_regiao
media_regional[municipios.iloc[0,0]] = taxa_media.round(2) # adicionando o par regiao:media no dicionario media regional
#print(f"Taxa media de pre-matricula na regiao {municipios.iloc[0,0]}: {taxa_media:.2f}")
# criando um data frame com as taxas medias para servir de base ao grafico de barras
regioes_df = pd.DataFrame({'taxa bruta media': [media_regional['Nordeste'], media_regional['Norte'],
media_regional['Centro-Oeste'], media_regional['Sul'],
media_regional['Sudeste']]},
index=['Nordeste', 'Norte', 'Centro-Oeste', 'Sul', 'Sudeste'])
regioes_df
| taxa bruta media | |
|---|---|
| Nordeste | 87.89 |
| Norte | 69.81 |
| Centro-Oeste | 80.38 |
| Sul | 86.84 |
| Sudeste | 87.76 |
Como demonstra o código acima, o tratamento de dados aqui utilizado consistiu em separar os municípios por região e, ao calcular a taxa bruta total em cada localidade, dividí-la pelo número de munícipios da região. Assim, obtemos a taxa bruta média por região, que nos permitiu construir o data frame 'regiões_df', para posteriormente usá-lo como base para a criação do gráfico de barras seguinte.
plt.figure(figsize=(12, 6))
plt.axhline(y=82.536, linewidth=4, color='r') # marcando uma linha com o valor mediano
sns.barplot(x=regioes_df.index, y=regioes_df['taxa bruta media'])
<matplotlib.axes._subplots.AxesSubplot at 0x1de1bed8100>
Um outro gráfico do relatório compara o ensino da rede pública e privada com dados escolares obtidos na base "basedosdados.br_inep_ideb.escola", encontrada no site base dos dados [https://basedosdados.org/]. Aqui o objetivo é demonstrar a diferença do conhecimento médio na área de matemática entre alunos da rede pública e de insituições privadas. O principal fator para demonstrar a dissemelhança são as notas saeb de matemática. Lembrando que saeb significa Sistema de Avaliação da Educação Básica. Os dados de interesse para a análise foram salvos em 'medias_data', carregando estes dados e observando suas linhas iniciais temos:
medias_data = pd.read_csv("notas_escolares_saeb.csv")
medias_data = medias_data.sort_values(by='ano')
medias_data.head()
| ano | id_municipio | id_escola | rede | anos_escolares | nota_saeb_matematica | indicador_rendimento | taxa_aprovacao | |
|---|---|---|---|---|---|---|---|---|
| 469827 | 2005 | 2913507 | 29331404 | municipal | finais (6-9) | NaN | NaN | NaN |
| 415512 | 2005 | 2924801 | 29076641 | municipal | finais (6-9) | NaN | NaN | NaN |
| 71622 | 2005 | 1503606 | 15100537 | municipal | finais (6-9) | 229.44 | 0.678964 | 66.4 |
| 230475 | 2005 | 2304400 | 23069953 | municipal | finais (6-9) | 230.61 | 0.533834 | 54.0 |
| 230484 | 2005 | 2304400 | 23069953 | municipal | iniciais (1-5) | 166.53 | 0.714928 | 71.9 |
Como a meta desta análise é comparar as notas das instituições públicas com as notas das instituições privadas, na coluna 'rede' vamos trocar o identificador por 'publica' sempre que aparecer 'municipal', 'estadual' ou 'federal'.
medias_data = medias_data.apply(set_rede, axis='columns')
medias_data.head()
| ano | id_municipio | id_escola | rede | anos_escolares | nota_saeb_matematica | indicador_rendimento | taxa_aprovacao | |
|---|---|---|---|---|---|---|---|---|
| 469827 | 2005 | 2913507 | 29331404 | publica | finais (6-9) | NaN | NaN | NaN |
| 415512 | 2005 | 2924801 | 29076641 | publica | finais (6-9) | NaN | NaN | NaN |
| 71622 | 2005 | 1503606 | 15100537 | publica | finais (6-9) | 229.44 | 0.678964 | 66.4 |
| 230475 | 2005 | 2304400 | 23069953 | publica | finais (6-9) | 230.61 | 0.533834 | 54.0 |
| 230484 | 2005 | 2304400 | 23069953 | publica | iniciais (1-5) | 166.53 | 0.714928 | 71.9 |
De acordo com o Inep, o Sistema de Avaliação da Educação básica é um exame voltado para as escolas da esfera pública, logo o número de escolas privadas que realizam este teste é muito menor que o de escolas da rede pública, essa informação se encontra em [https://academia.qedu.org.br/prova-brasil/o-que-e-a-prova-brasil/]. Dessa maneira, como existem somente cerca de 1700 escolas privadas nos dados analisados, selecionarei 2 mil escolas públicas dos anos de 2005, 2009, 2015 e 2019 (totalizando 8 mil escolas públicas), para comparar as notas médias na prova saeb de matemática dessas escolas com as particulares.
# selecionando um conjunto apenas com instituicoes publicas
notas_publicas = medias_data.loc[medias_data.rede == 'publica']
notas_publicas_2005 = notas_publicas.loc[notas_publicas.ano == 2005]
notas_publicas_2005 = notas_publicas_2005.iloc[35000:37000] # Como os conjuntos de notas publicas por ano tem em media 70 mil
# elementos, o intervalo 35000:37000 é um intervalo 'mediano'
notas_publicas_2009 = notas_publicas.loc[notas_publicas.ano == 2009]
notas_publicas_2009 = notas_publicas_2009.iloc[35000:37000]
notas_publicas_2015 = notas_publicas.loc[notas_publicas.ano == 2015]
notas_publicas_2015 = notas_publicas_2015.iloc[35000:37000]
notas_publicas_2019 = notas_publicas.loc[notas_publicas.ano == 2019]
notas_publicas_2019 = notas_publicas_2019.iloc[35000:37000]
amostra_anos = [notas_publicas_2005, notas_publicas_2009, notas_publicas_2015, notas_publicas_2019]
notas_rede_publica = pd.concat(amostra_anos) # criando um data frame com as notas dos anos escolhidos
# selecionando um conjunto apenas com instituicoes privadas
notas_rede_privada = medias_data.loc[medias_data.rede == 'privada']
data_publica_privada = [notas_rede_publica, notas_rede_privada]
data_final = pd.concat(data_publica_privada) # data frame com todos os dados a serem analisados
plt.figure(figsize=(12, 6))
sns.set(font_scale = 2.5)
sns.stripplot(x=data_final['rede'],
y=data_final['nota_saeb_matematica'],
s=4)
<matplotlib.axes._subplots.AxesSubplot at 0x1de1bb46dc0>
Uma fonte importante de informações para a análise feita no relatório é entender melhor sobre a remuneração dos docentes. Nesse aspecto, seria fundamental compreender quais são as faixas salariais mais comuns dos profissionais da educação, assim como qual o impacto na remuração, destes docentes possuírem ou não formação superior. Os dados analisados para a construção deste gráfico foram encontrados na base 'basedosdados.br_inep_indicadores_educacionais.brasil_remuneracao_docentes', presente no site [https://basedosdados.org/]. Os dados a serem analisados foram salvos em 'remuneracao_data', carregando esses dados e observando suas linhas iniciais:
remuneracao_data = pd.read_csv("docentes_remuneracao.csv")
remuneracao_data = remuneracao_data.sort_values(by="rem_media_40_horas_semanais")
remuneracao_data.head()
| ano | rede | numero_docentes | escolaridade | rem_media_40_horas_semanais | |
|---|---|---|---|---|---|
| 5 | 2014 | privada | 162623 | sem superior | 1668.337 |
| 19 | 2015 | privada | 167829 | sem superior | 1854.635 |
| 35 | 2016 | privada | 166167 | sem superior | 2004.143 |
| 12 | 2014 | municipal | 320619 | sem superior | 2152.361 |
| 48 | 2017 | privada | 163549 | sem superior | 2176.979 |
Para entendermos o cenário atual, é interessante observarmos a média salarial não no ano de 2021 mas sim num período anterior, por isso, para estabelecer a comparação citada anteriormente, foi aqui escolhido o ano de 2014. Vamos começar selecionando os dados referentes ao ano de 2014 em relação aos docentes sem e com ensino superior completo.
remuneracao_2014_sem_superior = remuneracao_data.loc[(remuneracao_data.ano == 2014) &
(remuneracao_data.escolaridade == "sem superior")]
remuneracao_2014_superior = remuneracao_data.loc[(remuneracao_data.ano == 2014) &
(remuneracao_data.escolaridade == "superior")]
Vamos agora observar estes conjuntos de dados para tentar identificar faixas de salário médio dos profissionais com e sem ensino superior completo.
remuneracao_2014_sem_superior
| ano | rede | numero_docentes | escolaridade | rem_media_40_horas_semanais | |
|---|---|---|---|---|---|
| 5 | 2014 | privada | 162623 | sem superior | 1668.337 |
| 12 | 2014 | municipal | 320619 | sem superior | 2152.361 |
| 7 | 2014 | publica | 386924 | sem superior | 2184.189 |
| 9 | 2014 | estadual | 65545 | sem superior | 2265.883 |
| 1 | 2014 | federal | 760 | sem superior | 6950.498 |
Podemos notar que aproximadamente 160.000 docentes recebem por volta de 1700 reais mensalmente por uma jornada de 40 horas semanais. Da mesma maneira, cerca de 320.000 recebem em torno de 2150 reais mensais. Assim, podemos criar um dicionário contendo faixas salariais médias, que posteriormente será usado para formar o gráfico de Kernel Density.
"""cada par chave-valor do dicionario indica a faixa salarial e quantos docentes aproximadamente recebem aquele valor
o primeiro item do dicionario, por exemplo, indica que 160.000 docentes recebem R$ 1700.00"""
salarios_sem_superior = {'faixa_1': [1700] * 160000, 'faixa_2': [2150] * 320000, 'faixa_3': [2180] * 380000,
'faixa_4': [2300] * 65000}
remuneracao_2014_superior
| ano | rede | numero_docentes | escolaridade | rem_media_40_horas_semanais | |
|---|---|---|---|---|---|
| 4 | 2014 | privada | 372093 | superior | 2996.662 |
| 13 | 2014 | municipal | 865923 | superior | 3408.914 |
| 8 | 2014 | publica | 1576739 | superior | 3562.692 |
| 11 | 2014 | estadual | 684292 | superior | 3572.709 |
| 2 | 2014 | federal | 26524 | superior | 7788.769 |
Seguindo um raciocínio análogo ao anterior, criamos um dicionário com as faixas salariais dos funcionários com ensino superior completo.
salarios_superior = {'faixa_1': [3000] * 370000, 'faixa_2': [3400] * 850000, 'faixa_3': [3600] * 650000,
'faixa_4': [3560] * 1500000}
Tendo em mãos agora todas as faixas salariais requeridas, podemos criar um data frame para cada dicionário.
# aqui o '*' (unpacking operator) é usado obtermos os elementos de cada faixa salarial (os elementos de cada lista)
faixas_superior = [*salarios_superior['faixa_1'], *salarios_superior['faixa_2'], *salarios_superior['faixa_3'],
*salarios_superior['faixa_4']]
# criando um data frame que recebe todos os salarios de todas as faixas
superior_data = pd.DataFrame({'Salarios ensino superior': [*faixas_superior]})
faixas_sem_superior = [*salarios_sem_superior['faixa_1'], *salarios_sem_superior['faixa_2'], *salarios_sem_superior['faixa_3'],
*salarios_sem_superior['faixa_4']]
sem_superior_data = pd.DataFrame({'Salarios sem ensino superior': [*faixas_sem_superior]})
plt.figure(figsize=(20, 12))
plt.title("Gráfico da distribuição salarial de docentes")
sns.kdeplot(data=superior_data['Salarios ensino superior'], label='com ensino superior', shade=True)
sns.kdeplot(data=sem_superior_data['Salarios sem ensino superior'], label='sem ensino superior', shade=True)
#sns.distplot(a=superior_data['Salarios ensino superior'], label="com ensino superior", kde=False)
#sns.distplot(a=sem_superior_data['Salarios sem ensino superior'], label="sem ensino superior", kde=False)
plt.legend()
<matplotlib.legend.Legend at 0x1de26b66e20>
É importante também buscarmos, ainda na análise dos docentes, a relação entre a rede de ensino do professor e a remuneração média recebida nesta. Para isto iremos usar a mesma base de dados descrita anteriormente, porém agora, como amostra, tomaremos a remuneração dos docentes no ano de 2015. Como já vimos que existe uma considerável diferença entre o salário dos professores com ou sem ensino superior, vamos agora analisar a distribuição salarial apenas entre os profissionais com ensino superior. Carregando os dados a serem analisados em "remuneracao_2015_com_superior" e observando este conjunto:
remuneracao_2015_com_superior = remuneracao_data.loc[(remuneracao_data.ano == 2015) &
(remuneracao_data.escolaridade == "superior")]
remuneracao_2015_com_superior
| ano | rede | numero_docentes | escolaridade | rem_media_40_horas_semanais | |
|---|---|---|---|---|---|
| 18 | 2015 | privada | 370433 | superior | 3290.569 |
| 29 | 2015 | municipal | 878227 | superior | 3760.544 |
| 25 | 2015 | estadual | 671806 | superior | 3859.379 |
| 23 | 2015 | publica | 1579846 | superior | 3911.689 |
| 17 | 2015 | federal | 29813 | superior | 9220.863 |
Para vizualizarmos melhor as informações trazidas pelo gráfico, vamos escolher 4 categorias da coluna rede e representarmos, num gráfico de setores, quantos profissionais atuam em cada área. Escolhemos então as categorias: privada, municipal, estadual e federal.
labels = ['rede - privada','rede - municipal','rede - estadual','rede - federal']
values = [370433, 878227, 671806, 29813] # quantidade de funcionarios nas redes privada, municipal, estadual e federal
# os valores recebidos na lista "pull" servem para 'separar' os setores do grafico, dando uma nocao maior da
# diferenca de tamanho entre eles
fig = go.Figure(data=[go.Pie(labels=labels, values=values, pull=[0.09, 0.09, 0.09, 0.09])])
fig.update_layout(
autosize=False,
width=800,
height=700,
title="Porcentagem de professores por rede",
legend_title="Rede",
font=dict(
family="Courier New, monospace",
size=20,
color="Black"
),
margin=dict(
l=80,
r=80,
b=100,
t=100,
pad=4
),
paper_bgcolor="LightSteelBlue",
)
colors = ['lightgreen', 'mediumturquoise', 'darkorange', 'gold']
fig.update_traces(hoverinfo='label+percent', textinfo='percent', textfont_size=20,
marker=dict(colors=colors, line=dict(color='#000000', width=2)))
fig.show()
A partir do gráfico anterior, notamos claramente que a faixa possuidora de menos docentes com ensino superior é a esfera federal. Agora, para clarificar o quão mais esses profissionais ganham em relação as outras categorias, vamos imaginar um salário médio total como sendo a soma dos salários médios em cada categoria, ou seja, usando o mesmo conjunto anterior:
remuneracao_2015_com_superior
| ano | rede | numero_docentes | escolaridade | rem_media_40_horas_semanais | |
|---|---|---|---|---|---|
| 18 | 2015 | privada | 370433 | superior | 3290.569 |
| 29 | 2015 | municipal | 878227 | superior | 3760.544 |
| 25 | 2015 | estadual | 671806 | superior | 3859.379 |
| 23 | 2015 | publica | 1579846 | superior | 3911.689 |
| 17 | 2015 | federal | 29813 | superior | 9220.863 |
Definimos que o salário médio total é:
salario_medio_total = 3290.569 + 3760.544 + 3859.379 + 9220.863
print(f"{salario_medio_total:.2f}")
20131.35
# agora o grafico levara em conta o salario medio para cada rede de ensino
labels = ['remuneracao - privada','remuneracao - municipal','remuneracao - estadual','remuneracao - federal']
values = [3290.569, 3760.544, 3859.379, 9220.863]
Vamos então gerar um gráfico de setores onde cada setor representa o remuneração média para cada uma das categorias de rede de ensino que estamos analisando.
fig = go.Figure(data=[go.Pie(labels=labels, values=values, pull=[0.09, 0.09, 0.09, 0.09])])
fig.update_layout(
autosize=False,
width=900,
height=800,
title="Porcentagem dos salarios por rede",
legend_title="Rede",
font=dict(
family="Courier New, monospace",
size=20,
color="Black"
),
margin=dict(
l=80,
r=80,
b=100,
t=100,
pad=4
),
paper_bgcolor="LightSteelBlue",
)
colors = ['lightgreen', 'mediumturquoise', 'darkorange', 'gold']
fig.update_traces(hoverinfo='label+percent', textinfo='percent', textfont_size=20,
marker=dict(colors=colors, line=dict(color='#000000', width=2)))
fig.show()
Durante o relatório foi importante evidenciar a possibilidade de acesso dos jovens estudantes a laboratórios de ciências e de informática. Para criar uma noção clara de como essa distribuição não abrange tantos estudantes, usei a biblioteca ploty.express para construir uma mapa do Brasil. A princípio, neste mapa ficará evidente quantos munícipios existem no Brasil e, posteriormente, será construído um outro mapa mostrando os municípios nos quais existem escolas que possuam algum laboratório de ciências ou de informática.
Para que possamos identificar todos os munícipos existentes no mapa do Brasil que será gerado, precisamos dos valores da latitude e da longitude de cada um destes municípios. Para isto, vamos carregar um arquivo csv contendo essas informações na variável 'municipios_data'. O arquivo csv contendo essas informações dos municípios foi criado com base nos dados disponibilizados pelo IBGE, e pode ser encontrado no link [https://github.com/kelvins/Municipios-Brasileiros/blob/main/README.md]. Observando as linhas iniciais desses dados temos:
municipios_data = pd.read_csv("municipios_coordenadas.csv")
municipios_data.head()
| codigo_ibge | nome | latitude | longitude | capital | codigo_uf | |
|---|---|---|---|---|---|---|
| 0 | 5200050 | Abadia de Goi�s | -16.75730 | -49.4412 | 0 | 52 |
| 1 | 3100104 | Abadia dos Dourados | -18.48310 | -47.3916 | 0 | 31 |
| 2 | 5200100 | Abadi�nia | -16.19700 | -48.7057 | 0 | 52 |
| 3 | 3100203 | Abaet� | -19.15510 | -45.4444 | 0 | 31 |
| 4 | 1500107 | Abaetetuba | -1.72183 | -48.8788 | 0 | 15 |
No trecho de código a seguir, 'scatter_mapbox' será responsável por gerar o mapa, 'plotando' neste diversos pontos coloridos, que identificam os municípios brasileiros. As coordenadas (latitude e longitude) desses pontos se encontram no data frame 'municipios_data' que foi passado como argumento para esta função. Adicionalmente, setamos 'lat' = latitude e 'lon' = longitude, para que as colunas de 'municipios_data' contendo as informações da latitude e longitude sejam reconhecidas. Assim, os pontos podem ser corretamente marcados.
fig = px.scatter_mapbox(municipios_data, lat="latitude", lon="longitude", hover_name="nome", hover_data=["codigo_uf"],
color_discrete_sequence=["fuchsia"], zoom=3, height=450)
fig.update_layout(mapbox_style="open-street-map")
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
Agora, para demonstrar a diferença entre quantos munícipios existem no Brasil, e quantos são aqueles nos quais existe ao menos uma escola que possua um laboratório de ciências ou de informática, vamos fazer uma análise conjunta de duas bases de dados. Primeiro a partir dos dados encontrados em 'basedosdados.br_inep_censo_escolar.escola', vamos analisar: quais escolas possuem pelo menos um laboratório de ciências ou de informática, e qual o código de identificação do município no qual essa escola se encontra. Salvando as informações de várias escolas do Brasil na variável 'laboratório_data' e observando algumas de suas linhas:
laboratorio_data = pd.read_csv("tipo_escola_laboratorio.csv")
laboratorio_data.tail()
| id_municipio | id_escola | tipo_categoria_escola_privada | laboratorio_ciencias | laboratorio_informatica | |
|---|---|---|---|---|---|
| 399995 | 1700400 | 17032601 | NaN | 0.0 | 0.0 |
| 399996 | 1702109 | 17005132 | 4.0 | 0.0 | 0.0 |
| 399997 | 1702109 | 17005140 | NaN | 0.0 | 0.0 |
| 399998 | 1702109 | 17005159 | NaN | 0.0 | 0.0 |
| 399999 | 1702109 | 17005175 | NaN | 0.0 | 0.0 |
Agora, vamos localizar em quais destas escolas existe pelo menos um laboratório. A seguir, criamos um conjunto com os identificadores dos municípios de todas essas escolas e verificamos se possuímos informações de todos esses municípios na base de dados que indica a latitude e a longitude destes.
presenca_laboratorios = laboratorio_data.loc[(laboratorio_data.laboratorio_ciencias != 0) &
(laboratorio_data.laboratorio_informatica != 0)]
# municipios nos quais existe pelo menos uma escola com laboratorio de ciencias ou de informatica
id_municipio_lab = presenca_laboratorios.id_municipio.unique()
# criando um conjunto tendo como elementos os codigos dos municipios em id_municipio_lab
conj_id_lab = set(id_municipio_lab)
# criando um conjunto tendo como elementos os codigos de todos os municipios da base de dados
conj_id_municipios = set(municipios_data.codigo_ibge)
# calculando a intersecao entre 'conj_id_lab' e 'conj_id_municipios', ou seja, vamos buscar se os municipios que possuem
# algum laboratorio estao todos listados na base de dados dos municipios
id_municipio_com_lab = conj_id_municipios.intersection(conj_id_lab)
# conferindo se todos os municipios com laboratorio foram encontrados na base de dados dos municipios
boolean_result = len(id_municipio_com_lab) == len(conj_id_lab)
boolean_result
True
Uma vez confirmado o fato de que todos os munícipios que desejamos plotar no gráfico possuem as coordenadas conhecidas, vamos criar um dataframe apenas com estas coordenas. Seria possível aqui também somente retirar de 'municipios_data' aqueles municípios cujas coordenadas não estão presentes em 'id_municipio_com_lab', porém para isto seria preciso percorrer linearmente cada uma das linhas do dataframe original ('municipios_data') e, para cada linha, verificar se as coordendas estão presentes em 'id_municipio_com_lab'. Esta técnica, entretanto, certamente resultaria numa complexidade elevada.
Logo, optei por criar um novo dataframe com as informações desejadas: 'nome', 'latitude', 'longitude', 'possui laboratorio'. Como a complexidade de consulta do nome de uma cidade em 'municipios_data' através das coordenadas é O(1), temos uma maneira mais eficiente de resolver o problema. Assim:
coordenadas = {'Nome': [], 'Latitude': [], 'Longitude': []}
for identificador in id_municipio_com_lab:
# localizando o municipio que possui laboratorio(s)
municipio_com_lab = municipios_data.loc[municipios_data.codigo_ibge == identificador]
lat, long = float(municipio_com_lab.latitude), float(municipio_com_lab.longitude)
nome = municipio_com_lab.iloc[0, 1] # o elemento na linha 0 e coluna 1 corresponde ao nome do municipio
coordenadas['Nome'].append(nome), coordenadas['Latitude'].append(lat), coordenadas['Longitude'].append(long)
municipios_com_lab_data = pd.DataFrame(coordenadas)
municipios_com_lab_data["Possui laboratorio"] = "Sim"
municipios_com_lab_data.head()
| Nome | Latitude | Longitude | Possui laboratorio | |
|---|---|---|---|---|
| 0 | Itaipava do Graja� | -5.14252 | -45.7877 | Sim |
| 1 | Bom Jardim da Serra | -28.33770 | -49.6373 | Sim |
| 2 | Manaquiri | -3.44078 | -60.4612 | Sim |
| 3 | Urubici | -28.01570 | -49.5925 | Sim |
| 4 | Lavandeira | -12.78470 | -46.5099 | Sim |
Agora que conhecemos todos os municípios nos quais existe pelo menos uma escola com laboratório, podemos usar esta nova informação (municipios_com_lab_data) para plotar um gráfico que destaque apenas tais municípios. Assim, será possível perceber a disparidade entre quantos municípios existem e quantos oferecem laboratório aos seus alunos.
fig = px.scatter_mapbox(municipios_com_lab_data, lat="Latitude", lon="Longitude", hover_name="Nome",
hover_data=["Possui laboratorio"], color_discrete_sequence=["fuchsia"], zoom=3, height=450)
fig.update_layout(mapbox_style="open-street-map")
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()